#include "svdpi.h"
#include "common.h"
typedef struct
{
    char fu;
    int rob_idx;
    long long int pc;
} DispatchEntry;

class Dispatch
{
public:
    int width;
    int data_num;
    std::vector<DispatchEntry> data;
    std::vector<bool> valid;
    Dispatch(int width)
    {
        resize(width);
    }
    ~Dispatch() = default;
    void clear()
    {
        data_num = 0;
        for (size_t i = 0; i < width; i++)
        {
            valid[i] = false;
        }
    }
    void resize(int width)
    {
        this->width = width;
        data.resize(width);
        valid.reserve(width);
        clear();
    }
    bool in(DispatchEntry entry)
    {
        if (data_num >= width)
            return false;
        data[data_num] = entry;
        valid[data_num] = true;
        data_num++;
        // LOG("In Fu %d", entry.fu);
        return true;
    }
    bool out(char ref_fu, DispatchEntry &entry)
    {
        bool success = false;
        if (data_num == 0)
            return false;
        for (size_t i = 0; i < width; i++)
        {
            if (valid[i] && data[i].fu == ref_fu)
            {
                valid[i] = false;
                success = true;
                entry = data[i];
                break;
            }
        }
        data_num--;
        // if (success)
        // {
        //     LOG("Out Fu %d", ref_fu);
        // }
        return success;
    }
};
static std::vector<Dispatch *> dispatchs;
static std::vector<std::string> dispatch_names;
static int dispatch_id = 0;
#ifdef __cplusplus
extern "C"
{
#endif
    int dispatch_create(int id, const char *name, int width)
    {
        if (id == 0)
        {
            dispatchs.push_back(new Dispatch(width));
            dispatch_names.push_back(std::string(name));
            dispatch_id++;
            LOG("Dispatch[%d] %s created", dispatch_id, name);
            return dispatch_id;
        }
        else
        {
            auto rob = dispatchs[id - 1];
            rob->clear();
            return id;
        }
    }
    void dispatch_in(int id, char fu, int rob_idx, long long pc)
    {
        // LOG("dispatch_in fu : %d", fu);

        if (id == 0)
            return;
        auto dispatch = dispatchs[id - 1];
        DispatchEntry entry;
        entry.fu = fu;
        entry.rob_idx = rob_idx;
        entry.pc = pc;
        bool success = dispatch->in(entry);
        Assert(success, "Dispatch %s data in num overflow", dispatch_names[id - 1].c_str());
    }
    void dispatch_out(int id, char ref_fu, char fu, int rob_idx, long long pc)
    {
        // LOG("dispatch_out ref_fu : %d", ref_fu);
        if (id == 0)
            return;
        auto dispatch = dispatchs[id - 1];
        DispatchEntry ref_entry = {0};
        bool success = dispatch->out(ref_fu, ref_entry);
        Assert(success, "Dispatch %s failed cause of ref could not found type %d op", dispatch_names[id - 1].c_str(), ref_fu);
        Assert(ref_entry.fu == fu, "Dispatch %s failed cause of ref fu %d != fu %d", dispatch_names[id - 1].c_str(), ref_entry.fu, fu);
        Assert(ref_entry.rob_idx == rob_idx, "Dispatch %s failed cause of ref rob_idx %d != rob_idx %d", dispatch_names[id - 1].c_str(), ref_entry.rob_idx, rob_idx);
        Assert(ref_entry.pc == pc, "Dispatch %s failed cause of ref pc %lld != pc %lld", dispatch_names[id - 1].c_str(), ref_entry.pc, pc);
    }
#ifdef __cplusplus
}
#endif